#include "vec2.h"
#include "vec3.h"
#include "vec4.h"
#include "dvec3.h"
#include "mat3.h"

namespace libvec
{
  vec3::vec3()
  {
    this->x = 0;
    this->y = 0;
    this->z = 0;
  }

  vec3::vec3(dvec3 v)
  {
    this->x = v.x;
    this->y = v.y;
    this->z = v.z;
  }

  vec3::vec3(vec4 v)
  {
    this->x = v.x;
    this->y = v.y;
    this->z = v.z;
  }

  vec3::vec3(float value)
  {
    this->x = value;
    this->y = value;
    this->z = value;
  }

  vec3::vec3(vec2 v, float z)
  {
    this->x = v.x;
    this->y = v.y;
    this->z = z;
  }

  vec3::vec3(float x, float y, float z)
  {
    this->x = x;
    this->y = y;
    this->z = z;
  }

  float &vec3::operator[](int index)
  {
    static float empty = 0;

    switch (index)
    {
      case 0:
        return this->x;

      case 1:
        return this->y;

      case 2:
        return this->z;
    }

    return empty;
  }

  vec3 vec3::operator=(vec3 v)
  {
    this->x = v.x;
    this->y = v.y;
    this->z = v.z;

    return *this;
  }

  vec3 vec3::operator=(dvec3 v)
  {
    this->x = v.x;
    this->y = v.y;
    this->z = v.z;

    return *this;
  }

  vec3 vec3::operator=(vec4 v)
  {
    this->x = v.x;
    this->y = v.y;
    this->z = v.z;

    return *this;
  }

  bool vec3::operator==(vec3 v)
  {
    return (this->x == v.x) && (this->y == v.y) && (this->z == v.z);
  }

  bool vec3::operator!=(vec3 v)
  {
    return (this->x != v.x) || (this->y != v.y) || (this->z != v.z);
  }

  vec3 &vec3::operator+()
  {
    return *this;
  }

  vec3 &vec3::operator-()
  {
    static vec3 out;

    out.x = -this->x;
    out.y = -this->y;
    out.z = -this->z;

    return out;
  }

  vec3 vec3::operator+(vec3 v)
  {
    vec3 out;

    out.x = this->x + v.x;
    out.y = this->y + v.y;
    out.z = this->z + v.z;

    return out;
  }

  vec3 vec3::operator+=(vec3 v)
  {
    this->x += v.x;
    this->y += v.y;
    this->z += v.z;

    return *this;
  }

  vec3 vec3::operator-(vec3 v)
  {
    vec3 out;

    out.x = this->x - v.x;
    out.y = this->y - v.y;
    out.z = this->z - v.z;

    return out;
  }

  vec3 vec3::operator-=(vec3 v)
  {
    this->x -= v.x;
    this->y -= v.y;
    this->z -= v.z;

    return *this;
  }

  vec3 vec3::operator*(mat3 m)
  {
    vec3 out;

    out.x = this->x*m.v1.x + this->y*m.v1.y + this->z*m.v1.z;
    out.y = this->x*m.v2.x + this->y*m.v2.y + this->z*m.v2.z;
    out.z = this->x*m.v3.x + this->y*m.v3.y + this->z*m.v3.z;

    return out;
  }

  vec3 vec3::operator*=(mat3 m)
  {
    vec3 out;

    this->x = this->x*m.v1.x + this->y*m.v1.y + this->z*m.v1.z;
    this->y = this->x*m.v2.x + this->y*m.v2.y + this->z*m.v2.z;
    this->z = this->x*m.v3.x + this->y*m.v3.y + this->z*m.v3.z;

    return out;
  }

  vec3 vec3::operator*(float scale)
  {
    vec3 out;

    out.x = this->x * scale;
    out.y = this->y * scale;
    out.z = this->z * scale;

    return out;
  }

  vec3 vec3::operator*=(float scale)
  {
    this->x *= scale;
    this->y *= scale;
    this->z *= scale;

    return *this;
  }

  vec3 vec3::operator/(float scale)
  {
    vec3 out;

    out.x = this->x / scale;
    out.y = this->y / scale;
    out.z = this->z / scale;

    return out;
  }

  vec3 vec3::operator/=(float scale)
  {
    this->x /= scale;
    this->y /= scale;
    this->z /= scale;

    return *this;
  }
}

